home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 SRC / Extensions / img / imgpgmmodule.c < prev    next >
Text File  |  1995-12-21  |  14KB  |  578 lines

  1. /***********************************************************
  2. Copyright 1991, 1992, 1993, 1994 by Stichting Mathematisch Centrum,
  3. Amsterdam, The Netherlands.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the names of Stichting Mathematisch
  12. Centrum or CWI not be used in advertising or publicity pertaining to
  13. distribution of the software without specific, written prior permission.
  14.  
  15. STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
  16. THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
  17. FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
  18. FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  19. WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  20. ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
  21. OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  22.  
  23. ******************************************************************/
  24.  
  25. #include "Python.h"
  26. #include "import.h"
  27. #include "pgm.h"
  28.  
  29. /* The image formats we support */
  30. static PyObject *format_grey, *format_xgrey, *format_grey_b2t, *format_choices;
  31. extern PyObject *getimgformat();    /* Get foirmat by name */
  32.  
  33. /*
  34. ** Since PBMPLUS error handling is abysmal (print message, exit),
  35. ** there is a modified version that has (slightly) better error
  36. ** handling. Contact jack@cwi.nl if you want it. Define PBMNEWERROR
  37. ** if you have the modified pbmplus.
  38. **
  39. ** If you don't have it the first pbm error will abort you python
  40. ** program.
  41. */
  42. #define PBMNEWERROR
  43.  
  44. #ifndef PBMNEWERROR
  45. #define PGM_END
  46. #define PGM_START if (0) {
  47. #define PGM_ENDSTART }
  48.  
  49. #else
  50.  
  51. #include <setjmp.h>
  52. jmp_buf pgmerrenv;
  53. char pgmerrstr[1000];
  54.  
  55. #define PGM_END pm_setmsghandler(0); pm_setexithandler(0);
  56. #define PGM_START if ( setjmp(pgmerrenv) != 0 ) { \
  57.         PyErr_SetString(errobject, pgmerrstr); \
  58.     *pgmerrstr = '\0'; \
  59.         PGM_END
  60. #define PGM_ENDSTART return 0; \
  61.     } \
  62.     pm_setmsghandler(my_pmerr); \
  63.     pm_setexithandler(my_pmexit);
  64.  
  65.  
  66. static void
  67. my_pmerr(str)
  68.     char *str;
  69. {
  70.     strncpy(pgmerrstr, str, 999);
  71. }
  72.  
  73. static void
  74. my_pmexit()
  75. {
  76.     longjmp(pgmerrenv, 1);
  77. }
  78.  
  79. #endif /* PBMNEWERROR */
  80.  
  81. /* Pgm objects */
  82.  
  83. typedef struct {
  84.     PyObject_HEAD
  85.     PyObject    *dict;        /* Attributes dictionary */
  86.     int    is_reader;    /* TRUE if this is a reader */
  87.     char    *filename;    /* filename of the image file */
  88.     FILE    *filep;
  89.     gray    maxval;
  90.     int    format;
  91. } pgmobject;
  92.  
  93. static PyObject *errobject;
  94.  
  95. staticforward PyTypeObject Pgmtype;
  96.  
  97. #define is_pgmobject(v)        ((v)->ob_type == &Pgmtype)
  98.  
  99. static char doc_pgm[] = "This object reads/writes PGM files\n"
  100.     "The 'width', 'height' and 'format' attributes describe the picture\n"
  101.     "For writers, setting 'forceplain' creates an ASCII PGM file.";
  102.  
  103. /* Routine to easily obtain C data from the dict python data */
  104. int
  105. pgmselfattr(self, name, fmt, ptr, wanterr)
  106.     pgmobject *self;
  107.     char *name;
  108.     char *fmt;
  109.     void *ptr;
  110.     int wanterr;
  111. {
  112.     PyObject *obj;
  113.     char errbuf[100];
  114.  
  115.     obj = PyDict_GetItemString(self->dict, name);
  116.     if ( obj == NULL ) {
  117.     if ( wanterr ) {
  118.         sprintf(errbuf, "Required attribute '%s' not set", name);
  119.         PyErr_SetString(errobject, errbuf);
  120.         return 0;
  121.     } else {
  122.         PyErr_Clear();
  123.         return 0;
  124.     }
  125.     }
  126.     if ( !PyArg_Parse(obj, fmt, ptr) ) {
  127.     if ( !wanterr )
  128.         PyErr_Clear();
  129.     return 0;
  130.     }
  131.     return 1;
  132. }
  133.  
  134. /* Routine to easily insert integer into dictionary */
  135. pgmsetintattr(self, name, value)
  136.     pgmobject *self;
  137.     char *name;
  138.     int value;
  139. {
  140.     PyObject *obj;
  141.     int rv;
  142.  
  143.     obj = PyInt_FromLong(value);
  144.     rv = PyDict_SetItemString(self->dict, name, obj);
  145.     Py_DECREF(obj);
  146.     return rv;
  147. }
  148.  
  149. static pgmobject *
  150. newpgmobject()
  151. {
  152.     pgmobject *xp;
  153.     xp = PyObject_NEW(pgmobject, &Pgmtype);
  154.     if (xp == NULL)
  155.         return NULL;
  156.     xp->dict = PyDict_New();
  157.     xp->filename = NULL;
  158.     xp->filep = NULL;
  159.     return xp;
  160. }
  161.  
  162. static int
  163. initpgmreader(self, name)
  164.     pgmobject *self;
  165.     char *name;
  166. {
  167.     char *name_copy;
  168.     int cols, rows;
  169.     gray old_pbmmaxval;
  170.  
  171.     if( (name_copy=malloc(strlen(name)+1)) == NULL ) {
  172.     PyErr_NoMemory();
  173.     return 0;
  174.     }
  175.     strcpy(name_copy, name);
  176.     self->filename = name_copy;
  177.     self->is_reader = 1;
  178.  
  179.     if ((self->filep = fopen(self->filename, "rb")) == NULL ) {
  180.     PyErr_SetFromErrno(PyExc_IOError);
  181.     return 0;
  182.     }
  183.     PGM_START
  184.     fclose(self->filep);
  185.         self->filep = 0;
  186.     return 0;
  187.     PGM_ENDSTART
  188.     old_pbmmaxval = pgm_pbmmaxval;
  189.     pgm_pbmmaxval = 0xff;   /* XXXX Correct for grey/grey_b2t formats */
  190.     pgm_readpgminit(self->filep, &cols, &rows, &self->maxval,
  191.             &self->format);
  192.     pgm_pbmmaxval = old_pbmmaxval;
  193.     PGM_END
  194.  
  195.     pgmsetintattr(self, "width", cols);
  196.     pgmsetintattr(self, "height", rows);
  197.     PyDict_SetItemString(self->dict, "format", format_grey);
  198.     PyDict_SetItemString(self->dict, "format_choices", format_choices);
  199.     if ( PyErr_Occurred() )
  200.     return 0;
  201.     return 1;
  202. }
  203.  
  204. static int
  205. initpgmwriter(self, name)
  206.     pgmobject *self;
  207.     char *name;
  208. {
  209.     char *name_copy;
  210.  
  211.     if( (name_copy=malloc(strlen(name)+1)) == NULL ) {
  212.     PyErr_NoMemory();
  213.     return 0;
  214.     }
  215.     strcpy(name_copy, name);
  216.     self->filename = name_copy;
  217.     self->filep = NULL;
  218.     self->is_reader = 0;
  219.     PyDict_SetItemString(self->dict, "format", format_grey);
  220.     PyDict_SetItemString(self->dict, "format_choices", format_choices);
  221.     if( PyErr_Occurred())
  222.     return 0;
  223.     return 1;
  224. }
  225.  
  226. /* Pgm methods */
  227.  
  228. static void
  229. pgm_dealloc(xp)
  230.     pgmobject *xp;
  231. {
  232.     Py_XDECREF(xp->dict);
  233.     if( xp->filename )
  234.         free(xp->filename);
  235.     if( xp->filep )
  236.         fclose(xp->filep);
  237.     PyMem_DEL(xp);
  238. }
  239.  
  240. static char doc_read[] = "Read the actual data, returns a string";
  241.  
  242. static PyObject *
  243. pgm_read(self, args)
  244.     pgmobject *self;
  245.     PyObject *args;
  246. {
  247.         int i, w, h, toptobottom, rowlen;
  248.     PyObject *rv;
  249.     char *datap;
  250.     gray *pixelrow;
  251.     PyObject *fmt;
  252.     
  253.     if (!PyArg_ParseTuple(args,""))
  254.         return NULL;
  255.     if (!self->is_reader) {
  256.         PyErr_SetString(errobject, "Cannot read() from writer object");
  257.         return NULL;
  258.     }
  259.     /* XXXX Read data and return it */
  260.     /* XXXX Get args from self->dict and write the data */
  261.     if ( !pgmselfattr(self, "width", "i", &w, 1) ||
  262.          !pgmselfattr(self, "height", "i", &h, 1) ||
  263.          !pgmselfattr(self, "format", "O", &fmt, 1) )
  264.         return NULL;
  265.     if ( fmt == format_grey || fmt == format_xgrey )
  266.         toptobottom = 1;
  267.     else if ( fmt == format_grey_b2t )
  268.         toptobottom = 0;
  269.     else {
  270.         PyErr_SetString(errobject, "Unsupported image format");
  271.         return NULL;
  272.     }
  273.     pixelrow = 0;
  274.     rv = 0;
  275.     PGM_START
  276.         if ( pixelrow )
  277.         pbm_freerow(pixelrow);
  278.         if ( rv )
  279.         Py_DECREF(rv);
  280.         return NULL;
  281.     PGM_ENDSTART
  282.  
  283.     pixelrow=pgm_allocrow(w);
  284.  
  285.     if ( fmt == format_xgrey )
  286.         rowlen = w;
  287.     else
  288.         rowlen = (w+3) & ~3;  /* SGI images have 32bit aligned rows */
  289.     if ( (rv=PyString_FromStringAndSize(0, rowlen*h)) == NULL ) {
  290.         pbm_freerow(pixelrow);
  291.         return NULL;
  292.     }
  293.     datap = PyString_AsString(rv);
  294.  
  295.     if ( !toptobottom ) {
  296.         datap = datap + rowlen*(h-1);
  297.         rowlen = -rowlen;
  298.     }
  299.  
  300.     while( h > 0 ) {
  301.         pgm_readpgmrow(self->filep, pixelrow, w, self->maxval,
  302.                self->format);
  303.         for(i=0; i<w; i++)
  304.         datap[i] = pixelrow[i];
  305.         /* zero-out remaining bytes */
  306.         while(i<rowlen)
  307.         datap[i++] = 0;
  308.         datap += rowlen;
  309.         h -= 1;
  310.     }
  311.         PGM_END
  312.     pbm_freerow(pixelrow);
  313.     return rv;
  314. }
  315.  
  316. static char doc_write[] = "Write (string) data to the PGM file";
  317.  
  318. static PyObject *
  319. pgm_write(self, args)
  320.     pgmobject *self;
  321.     PyObject *args;
  322. {
  323.         unsigned char *data;
  324.     int datalen;
  325.     int i, w, h, rowlen;
  326.     PyObject *fmt;
  327.     gray *pixelrow;
  328.     int forceplain;
  329.     FILE *filep;
  330.     
  331.     if (!PyArg_ParseTuple(args, "s#", &data, &datalen))
  332.         return NULL;
  333.     if (self->is_reader) {
  334.         PyErr_SetString(errobject, "Cannot write() to reader object");
  335.         return NULL;
  336.     }
  337.     /* XXXX Get args from self->dict and write the data */
  338.     if ( !pgmselfattr(self, "width", "i", &w, 1) ||
  339.          !pgmselfattr(self, "height", "i", &h, 1) ||
  340.          !pgmselfattr(self, "format", "O", &fmt, 1) )
  341.         return NULL;
  342.  
  343.     forceplain = 0;
  344.     pgmselfattr(self, "forceplain", "i", &forceplain, 0);
  345.     if ( fmt == format_xgrey )
  346.         rowlen = w;
  347.     else
  348.         rowlen = (w+3) & ~3; /* For 32bit alignment of rows */
  349.  
  350.     if ( fmt != format_grey && fmt != format_xgrey &&
  351.          fmt != format_grey_b2t ) {
  352.         PyErr_SetString(errobject, "Unsupported image format");
  353.         return NULL;
  354.     }
  355.  
  356.     if( rowlen*h != datalen ) {
  357.         PyErr_SetString(errobject, "Incorrect datasize");
  358.         return NULL;
  359.     }
  360.         
  361.     if ( fmt == format_grey_b2t ) {
  362.         data = data + rowlen*(h-1);
  363.         rowlen = -rowlen;
  364.     }
  365.  
  366.     if ((filep = fopen(self->filename, forceplain?"w":"wb")) == NULL) {
  367.         PyErr_SetFromErrno(PyExc_IOError);
  368.         return 0;
  369.     }
  370. #ifdef macintosh
  371.     setfiletype(self->filename, '????', 'PPGM');
  372. #endif
  373.  
  374.     pixelrow = 0;
  375.     PGM_START
  376.         if ( pixelrow )
  377.         pbm_freerow(pixelrow);
  378.         fclose(filep);
  379.         return NULL;
  380.     PGM_ENDSTART
  381.  
  382.     pixelrow=pgm_allocrow(w);
  383.  
  384.     pgm_writepgminit(filep, w, h, 0xff, forceplain);
  385.     while( h > 0 ) {
  386.         for(i=0; i<w; i++)
  387.         pixelrow[i] = data[i];
  388.         pgm_writepgmrow(filep, pixelrow, w, 0xff, forceplain);
  389.         data += rowlen;
  390.         h -= 1;
  391.     }
  392.     PGM_END
  393.     pbm_freerow(pixelrow);
  394.     if (fclose(filep) != 0) {
  395.         PyErr_SetFromErrno(PyExc_IOError);
  396.         return NULL;
  397.     }
  398.     Py_INCREF(Py_None);
  399.     return Py_None;
  400. }
  401.  
  402. static struct PyMethodDef pgm_methods[] = {
  403.     {"read",    (PyCFunction)pgm_read,    1,    doc_read},
  404.     {"write",    (PyCFunction)pgm_write,    1,    doc_write},
  405.     {NULL,        NULL}        /* sentinel */
  406. };
  407.  
  408. static PyObject *
  409. pgm_getattr(xp, name)
  410.     pgmobject *xp;
  411.     char *name;
  412. {
  413.         PyObject *v;
  414.     
  415.     if (xp->dict != NULL) {
  416.             if ( strcmp(name, "__dict__") == 0 ) {
  417.                 Py_INCREF(xp->dict);
  418.             return xp->dict;
  419.         }
  420.                if ( strcmp(name, "__doc__") == 0 ) {
  421.                 return PyString_FromString(doc_pgm);
  422.         }
  423.         v = PyDict_GetItemString(xp->dict, name);
  424.         if (v != NULL) {
  425.             Py_INCREF(v);
  426.             return v;
  427.         }
  428.     }
  429.     return Py_FindMethod(pgm_methods, (PyObject *)xp, name);
  430. }
  431.  
  432. static int
  433. pgm_setattr(xp, name, v)
  434.     pgmobject *xp;
  435.     char *name;
  436.     PyObject *v;
  437. {
  438.     if (xp->dict == NULL) {
  439.         xp->dict = PyDict_New();
  440.         if (xp->dict == NULL)
  441.             return -1;
  442.     }
  443.     if (v == NULL) {
  444.         int rv = PyDict_DelItemString(xp->dict, name);
  445.         if (rv < 0)
  446.             PyErr_SetString(PyExc_AttributeError,
  447.                     "delete non-existing imgpgm attribute");
  448.         return rv;
  449.     }
  450.     else
  451.         return PyDict_SetItemString(xp->dict, name, v);
  452. }
  453.  
  454. static PyTypeObject Pgmtype = {
  455.     PyObject_HEAD_INIT(&PyType_Type)
  456.     0,            /*ob_size*/
  457.     "imgpgm",        /*tp_name*/
  458.     sizeof(pgmobject),    /*tp_basicsize*/
  459.     0,            /*tp_itemsize*/
  460.     /* methods */
  461.     (destructor)pgm_dealloc, /*tp_dealloc*/
  462.     0,            /*tp_print*/
  463.     (getattrfunc)pgm_getattr, /*tp_getattr*/
  464.     (setattrfunc)pgm_setattr, /*tp_setattr*/
  465.     0,            /*tp_compare*/
  466.     0,            /*tp_repr*/
  467.     0,            /*tp_as_number*/
  468.     0,            /*tp_as_sequence*/
  469.     0,            /*tp_as_mapping*/
  470.     0,            /*tp_hash*/
  471. };
  472.  
  473. static char doc_newreader[] =
  474.     "Return an object that reads the PGM/PBM file passed as argument";
  475.  
  476. static PyObject *
  477. pgm_newreader(self, args)
  478.     PyObject *self;
  479.     PyObject *args;
  480. {
  481.         char *filename;
  482.     pgmobject *obj;
  483.     
  484.     if (!PyArg_ParseTuple(args, "s", &filename))
  485.         return NULL;
  486.     if ((obj = newpgmobject()) == NULL)
  487.         return NULL;
  488.     if ( !initpgmreader(obj, filename) ) {
  489.         pgm_dealloc(obj);
  490.         return NULL;
  491.     }
  492.     return (PyObject *)obj;
  493. }
  494.  
  495. static char doc_newwriter[] =
  496.     "Return an object that writes the PGM file passed as argument";
  497.  
  498. static PyObject *
  499. pgm_newwriter(self, args)
  500.     PyObject *self;
  501.     PyObject *args;
  502. {
  503.         char *filename;
  504.     pgmobject *obj;
  505.     
  506.     if (!PyArg_ParseTuple(args, "s", &filename))
  507.         return NULL;
  508.     if ((obj = newpgmobject()) == NULL)
  509.         return NULL;
  510.     if ( !initpgmwriter(obj, filename) ) {
  511.         pgm_dealloc(obj);
  512.         return NULL;
  513.     }
  514.     return (PyObject *)obj;
  515. }
  516.  
  517.  
  518. /* List of functions defined in the module */
  519.  
  520. static struct PyMethodDef pgm_module_methods[] = {
  521.     {"reader",    pgm_newreader,    1,    doc_newreader},
  522.     {"writer",    pgm_newwriter,    1,    doc_newwriter},
  523.     {NULL,        NULL}        /* sentinel */
  524. };
  525.  
  526.  
  527. /* Initialization function for the module (*must* be called initimgpgm) */
  528. static char doc_imgpgm[] =
  529.   "Module that reads images from PGM/PBM files and writes to PGM files.";
  530.  
  531.  
  532. void
  533. initimgpgm()
  534. {
  535.     PyObject *m, *d, *x, *formatmodule, *formatdict;
  536.  
  537.     /* Create the module and add the functions */
  538.     m = Py_InitModule("imgpgm", pgm_module_methods);
  539.  
  540.     /* Add some symbolic constants to the module */
  541.     d = PyModule_GetDict(m);
  542.     errobject = PyString_FromString("imgpgm.error");
  543.     PyDict_SetItemString(d, "error", errobject);
  544.     x = PyString_FromString(doc_imgpgm);
  545.     PyDict_SetItemString(d, "__doc__", x);
  546.  
  547.     /* Get supported formats */
  548.     if ((formatmodule = PyImport_ImportModule("imgformat")) == NULL)
  549.         Py_FatalError("imgpgm depends on imgformat");
  550.     if ((formatdict = PyModule_GetDict(formatmodule)) == NULL)
  551.         Py_FatalError("imgformat has no dict");
  552.  
  553.     format_grey = PyDict_GetItemString(formatdict,"grey");
  554.     format_xgrey = PyDict_GetItemString(formatdict,"xgrey");
  555.     format_grey_b2t = PyDict_GetItemString(formatdict,"grey_b2t");
  556.     format_choices = Py_BuildValue("(OOO)", format_grey, format_xgrey,
  557.                  format_grey_b2t);
  558.  
  559.     /* Initialize pbmplus */
  560.         {
  561.         int pgm_argc;
  562.         static char *pgm_arglist[] = { "pbmplus", 0};
  563.         char **pgm_argv;
  564.  
  565.         pgm_argc = 1;
  566.         pgm_argv = pgm_arglist;
  567.         PGM_START /* { */
  568.         Py_FatalError("pbmplus initialization error");
  569.         } /* PGM_ENDSTART won't work here, it has return NULL */
  570.         pgm_init(&pgm_argc, pgm_argv);
  571.         PGM_END
  572.     }
  573.  
  574.     /* Check for errors */
  575.     if (PyErr_Occurred())
  576.         Py_FatalError("can't initialize module imgpgm");
  577. }
  578.